package com.zy.explore.db.infrastructure.plugins.multidbsupport.sqlchange.function;

import org.apache.commons.lang3.StringUtils;

import java.util.List;

/**
 * 建类说明：mysql甲骨文乐趣改变工厂
 *
 * @author 中国印
 * @date 2022年02月16日 23:12:13
 */
public class MysqlToOracleFunChangeFactory extends AbstractFunChangeFactory {

    public MysqlToOracleFunChangeFactory() {
        init();
    }

    private void init() {
        // 菜鸟教程 MySQL 函数
        // https://www.runoob.com/mysql/mysql-functions.html

        // CHAR_LENGTH(s) 返回字符串 s 的字符数
        add("char_length", fun -> merge("length", fun.getArgList()));

        // 函数可以将数字 x 进行格式化 "#,###.##", 将 x 保留到小数点后 n 位，最后一位四舍五入。
        add("format", fun -> {
            if (fun.getArgList().size() != 2) {
                //只比较2个参数
                return null;
            }
            String format = fun.getArgList().get(1);
            if (format.indexOf('%') > 0) {
                //日期格式
                format = dateFormatUpdate(format);
                return merge("to_date", fun.getArgList().get(0), format);
            } else {
                return null;
            }
        });

        add("CONVERT", fun -> null);
        //返回参数中的第一个非空表达式（从左向右）
        add("COALESCE", fun -> null);
        add("instr", fun -> null);
        add("CONCAT_WS", fun -> null);
        add("stuff", fun -> null);
        add("DateName", fun -> null);
        //空值转换
        // add("ifnull",fun->{
        // 	return merge("nvl",fun.getArgList());
        // });
        //日期转字符串
        add("date_format", fun -> {
            List<String> argList = fun.getArgList();
            //只识别2个参数
            if (argList.size() != 2) {
                return null;
            }
            String format = argList.get(1);

            if ("'%Y-%m-%d'".equals(format) && argList.get(0).toLowerCase().endsWith("create_date")) {
                //由于代码中create_date存在大量字符串格式的日期和时间使用%Y-%m-%d转换为日期，
                //所以将参数强制截取10个字符长度
                return merge("substr", argList.get(0), "1", "10");
            }
            if ("'%Y-%m'".equals(format) && argList.get(0).toLowerCase().endsWith("create_date")) {
                //由于代码中create_date存在大量字符串格式的日期和时间使用%Y-%m-%d转换为日期，
                //所以将参数强制截取7个字符长度
                return merge("substr", argList.get(0), "1", "7");
            }
            format = dateFormatUpdate(format);
            return merge("to_char", argList.get(0), format);
        });
		//字符转时间
        add("str_to_date", fun -> {
            List<String> argList = fun.getArgList();
			//只识别2个参数
            if (argList.size() != 2) {
                return null;
            }
            String format = argList.get(1);
            format = dateFormatUpdate(format);
            return merge("to_date", argList.get(0), format);
        });
		//字符串拼接
        add("concat", fun -> {
            List<String> argList = fun.getArgList();
			//2个以下参数不需要转换
            if (argList.size() < 3) {
                return null;
            }

            return concat(argList, 0);
        });
		//列合并 数据库只支持一个参数，并且不支持分割符号
        add("group_concat", fun -> {
            String arg0 = fun.getArgList().get(0);
            //listagg 支持分割符
            int idx = StringUtils.indexOfIgnoreCase(arg0, " separator ");
            if (idx > -1) {
                fun.getArgList().set(0, arg0.substring(0, idx));
            } else if (StringUtils.indexOfIgnoreCase(arg0, " order ") > 0) {
                //简化版，暂不考虑排序
                fun.getArgList().set(0, arg0.substring(0, StringUtils.indexOfIgnoreCase(arg0, " order ")));
            }
            return merge("wm_concat", fun.getArgList());
        });
		//DATE() 函数返回日期或日期/时间表达式的日期部分。
        add("date", fun -> {
            String arg0 = fun.getArgList().get(0);
            return merge("to_char", arg0, "'yyyy-mm-dd'");
        });
        add("date_sub", fun -> {
            if (fun.getArgList().size() != 2) {
                //只处理两个参数
                return null;
            }
            String arg0 = fun.getArgList().get(0);
            String arg1 = fun.getArgList().get(1);
            String[] ss = arg1.split("\\s+");
            if (ss.length != 3 || !ss[0].equalsIgnoreCase("interval")) {
                return null;
            }
            String numStr = ss[1];
            if (numStr.charAt(0) == '-') {
                numStr = numStr.substring(1);
            } else {
                numStr = "-" + numStr;
            }
            switch (ss[2].toLowerCase()) {
                case "hour":
                    return arg0 + " " + numStr + "/24";
                case "day":
                    return arg0 + " " + numStr;
                case "month":
                    return merge("add_months", arg0, numStr);
                case "year":
                    return merge("add_months", arg0, numStr + " * 12");
                default:
                    return null;
            }
        });
    }

    /**
     * 日期格式修改
     */
    private String dateFormatUpdate(String format) {
        if ("'%Y-%m-%d'".equals(format)) {
            format = "'yyyy-mm-dd'";
        } else {
            format = format.replaceAll("%Y", "yyyy");
            format = format.replaceAll("%m", "mm");
            format = format.replaceAll("%d", "dd");
            format = format.replaceAll("%H", "hh24");
            format = format.replaceAll("%i", "mi");
            format = format.replaceAll("%s", "ss");
        }
        return format;
    }

    private String concat(List<String> argList, int start) {
		//倒数两个参数
        if (start + 2 == argList.size()) {
            return "concat(" + argList.get(start) + "," + argList.get(start + 1) + ")";
        }
        return "concat(" + argList.get(start) + "," + concat(argList, start + 1) + ")";
    }
}
